Appendix II

 C Code Usage

 t General Remarks

 t Writing XPrims

 t Writing XCode

*521*

Both the Prograph interpreter and the Prograph compiler allow you to import code written in C. There are two different formats for writing imported C code. One is used for writing external primitives (XPrims), which can be included in the Prograph environment, much like XCMDs are included in HyperCard. The other format is used for writing external code (XCode) which is linked by the compiler into your final application. 

XPrims allow you to define Prograph primitives which can be used in both interpreted and compiled code. XCode allows greater access to Prograph language elements such as methods, attributes and persistents. However, XCode can be used only in compiled code.

Both XPrims and XCode may be written in either MPW C or THINK C. THINK C object extensions may be used in XCode. 

_______________________________________
NOTE:    The Prograph C Interfaceerface allows you to access existing C  libraries from the Prograph interpreter and compiler. It is available directly from Prograph International. 
---------------------------------------

t
General Remarks  *521*

In this section we discuss matters which are pertinent to both XPrims and XCode written in either MPW C or THINK C. A good understanding of the topics covered in this section is necessary before writing C code to be imported by Prograph.

 Naming Conventions  *522*

In compiled code the interface between Prograph and C is provided through a set of naming conventions. These conventions allow you to access and define Prograph language elements such as methods, attributes, and persistents in C. 

In compiled code, primitives use the same naming convention as universal methods (in fact, the Prograph compiler makes no distinction between primitives and universal methods). In order for XPrims to run in interpreted and compiled code they must be named according to the naming conventions for universal methods.

A universal method is a function with a name of the form U_id. A persistent is a global variable with a name of the form P_id.  Each Prograph class has a default instance which is a global variable of the form C_class__A_default. Class attributes are global variables of the form C_class__A_id. In Prograph there are four types of class methods:   simple (or plain), initialization, get and set. Class methods are C functions with names of the form:   C_class__M_id (simple), C_class__N_ (initialization), C_class__G_id (get), and C_class__S_id (set). In C, two other types of class methods may be defined:   default get methods and default set methods which have the forms C_class__g_id and C_class__s_id respectively. A Prograph class has an associated class identifier which is a global variable of the form C_id__.

Any non-alphanumeric character in a name must be replaced by the two-character, hexadecimal ASCII code and delimited by underscores. For example, the universal method point-in-rect? is represented as U_point_2D_in_2D_rect_3F_ ( 2D and 3F being the ASCII representations of '-' and '?' respectively).

In XCode, Prograph classes and class methods may be accessed directly through THINK classes.

The use of these naming conventions is discussed in detail in the section on XCode. 

 Prograph Data Types *522*

In this section the Prograph data types are discussed in general terms. Actual C definitions of the data types, which differ between interpreted XPrims, compiled XPrims, and XCode, are given in later sections.

For portability all Prograph data types are based upon the following set of fundamental C types. *523*

typedef char Int1;
      /* integer 1 byte */
typedef short Int2;
     /* integer 2 byte*/
typedef long Int4;
      /* integer 4 byte*/

typedef unsigned char Nat1;
  /* natural 1 byte */
typedef unsigned short Nat2;
 /* natural 2 byte */
typedef unsigned long Nat4;
  /* natural 4 byte */

typedef float Real4;
     /* real 4 byte */
typedef short double Real8;
  /* real 8 byte */
typedef double Real10;
    /* real 10 byte */

typedef Nat2 Bool;
      /* boolean 2 byte */

Prograph uses eight basic data types and one special data type called the NULL type. All of the data types are implemented as handles except the NULL type which is implemented as a zero value. *523*

Type
Interpreted XPrims
Compiled XPrims
XCode 

C_boolean TRUE = 1, FALSE = 0
TRUE = 1, FALSE = 0
TRUE = 1, FALSE = 0

C_instance 0 to 65534 attributes
232 - 1 attributes
232 - 1 attributes

C_integer signed four-byte integer
signed four-byte integer
signed four-byte integer

C_list 0 to 65535 list elements
232 - 1 list elements
232 - 1 list elements

C_none no value
no value
no value

C_real 10-byte SANE extended real
10-byte SANE extended real
10-byte SANE extended real

C_string 0 to 65535 characters
232 - 1 characters
232 - 1 characters

C_undefined  no value
no value
no value

With the exception of the NULL type all Prograph data types have three fields in common:   type, save and use. *523*

The type field identifies the data type. The contents of this field should never be accessed directly; use the supplied functions IsType, HasType and GetRefLevel or the supplied macro INCLASS (described below) instead.*524*

The save field is used by Prograph during loading and saving of files, and when cycles in data linkage need to be detected. The save field is for internal use by Prograph only.

The use field contains the data item’s “use count”, which is the number of references to this item. The section “Use Counts” below explains this important concept. 
An abstract data type, C_object, which has only type, save and use fields, is provided for declarations of variables of undetermined type. 

The C_none and C_undefined data types consist only of a type, save and use field.

The C_boolean type has a value field that contains one to indicate TRUE, or zero for FALSE.*524*

The C_integer type has a value field that contains any 32-bit integer.

The C_real has a value field that contains any valid SANE (10-byte) extended real number.  (For details on the SANE extended real, see The Apple Numerics manual.)
Prograph lists are implemented as arrays (rather than as linked lists). The C_list type contains a length field indicating the number of elements in the list. A length of ten indicates ten values in the list, and a length of zero indicates no entries, or the empty list. 

The length field is followed by the data field, a variable-length array of four-byte entries. Each entry, or slot, in the data array is either a handle to a data item or NULL. 

Prograph treats the first element of a list as index one, but C treats the first element as index zero. A primitive written in C should therefore subtract one from an index passed in from Prograph as an argument. Similarly, an index returned as output should have the value one added to it.

Strings are represented by the C_string type. C_strings are similar in structure to C_lists except that, instead of an array of four-byte slots, they have an array of one-byte characters in the field text. A C_string with length zero is the empty string.*524*

Instances of user-defined classes are implemented as type C_instance. The C_Instance type contains a field attrs which is an array of data items.  The array elements correspond, in order, to the instance attributes defined for the class.  As with lists, this array is zero-based.

Macintosh Data Types *525*

Macintosh data types differ between compiled code and interpreted code. In this section we discuss what is common to both. Actual C definitions of the structures are given in the following section. 

Macintosh-dependent data types are stored in structures each of which has a type, save, use and value field. The value field of each Macintosh data type has a different underlying C type. For example, a C_Point has a value field of type Point and a C_EventRecord has a value field of type EventRecord.

The structure C_ABlock is available for macintosh data of an unsupported type. The value field of C_ABlock is an array of bytes. The primitive new-block is provided for the creation of ABlocks.

The data types C_Ptr and C_Handle have value fields which are macintosh pointers and handles respectively. These may be pointers and handles to any type of macintosh data. C_Ptr and C_Handle also have a field which indicates the type of the data which is pointed to. 

The HasType and GetRefLevel supplied functions (described below) allow you to determine the the level of indirection and the underlying macintosh type of any Macintosh data item. 

Data Types in XPrims *525*

This section describes C declarations of the Prograph data types for XPrims. Although the declarations differ between interpreted and compiled code, these differences will be transparent if only common fields are used. 

The save and use fields are two bytes in interpreted code but four bytes in compiled code. The same is true of the length fields of the C_string and C_list types. The C_instance data type has two extra fields in interpreted code. Macintosh types have several differences; declarations are shown for C_Point, C_Ptr and C_Handle.

Note that all Prograph data types are declared as pointers but are implemented as handles. This is to preserve compatibility with THINK C object extensions. The following example shows how a parameter of type C_object is declared.*525*

 U_sample_20_method( anObject )
 C_object *anObject;
    /* anObject is a Handle */
 
 ...

Each type has a structure name of the form CS_name. This is required in interpreted XPrim code by the supplied functions which create data items.

XPrim interpreted code declarations:  *526*

 typedef struct
  /* C_object - INTERPRETED XPrims */
 
  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
   *C_object;
 typedef struct
  /* C_none - INTERPRETED XPrims */

  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
  CS_none, *C_none;

 typedef struct
  /* C_undefined - INTERPRETED XPrims */
 
  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
  CS_undefined, *C_undefined;
 
 typedef struct
  /* C_boolean - INTERPRETED XPrims */
 
  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
  Bool
value;
  CS_boolean, *C_boolean;

 typedef struct
  /* C_integer - INTERPRETED XPrims */
 
  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
  Int4
 value;
  CS_integer, *C_integer;

 typedef struct
  /* C_real - INTERPRETED XPrims */
 
  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
  Real10
value;
  CS_real, *C_real;
 typedef struct
  /* C_list - INTERPRETED XPrims */
 
  Int2
 type;
/* internal use only */
  Nat2
 save;
/* internal use only */
  Nat2
 use;
/* number of references */
  Nat2
 length; /* length of list  */
  C_object
*data[];
  CS_list, *C_list;
 typedef struct
  /* C_string - INTERPRETED XPrims */
 
  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
  Nat2
length; /* length of string */
  Nat1
text[];
  CS_string, *C_string;
 
 typedef struct
  /* C_instance - INTERPRETED XPrims */
 
  Int2
type;
/* internal use only */
  Nat2
save;
/* internal use only */
  Nat2
use;
/* number of references */
  Nat2
size;
/* Interpreted only (# of attributes +1)*/
  Handle
 class;
/* Interpreted only */
  C_object
*attrs[];
  CS_instance, *C_instance;
 
 typedef struct
/* C_Point - INTERPRETED XPrims */
 
  Int2
type;
 /* internal use only  */ 
  
  Nat2
save;
 /* internal use only */
  
  Nat2
use;
 /* number of references */
  
  Nat2
size;
 /* Interpreted only */
 
  Int2
mactype; /* Interpreted only */
  Point
value;
  CS_Point, *C_Point;
 
 typedef struct
/* C_Ptr - INTERPRETED XPrims */
 
  Int2
type;
 /* internal use only  */ 
  
  Nat2
save;
 /* internal use only */
  
  Nat2
use;
 /* number of references */
  
  Nat2
size;
 /* Interpreted only */
 
  Int2
mactype; /* Interpreted only */
  Ptr
value;
  CS_Ptr, *C_Ptr;
 
 typedef struct
/* C_Handle - INTERPRETED XPrims */
 
  Int2
type;
 /* internal use only  */ 
  
  Nat2
save;
 /* internal use only */
  
  Nat2
use;
 /* number of references */
  
  Nat2
size;
 /* Interpreted only */
 
  Int2
mactype; /* Interpreted only */
  Handle
value;
  CS_Handle, *C_Handle;

XPrim compiled code declarations:    *528*

 typedef struct
  /* C_object - COMPILED XPrims */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
   *C_object;

 typedef struct
  /* C_none - COMPILED XPrims */

  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  *C_none;

 typedef struct
  /* C_undefined - COMPILED XPrims */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  *C_undefined;
 
 typedef struct
  /* C_boolean - COMPILED XPrims */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Bool
value;
  *C_boolean;

 typedef struct
  /* C_integer - COMPILED XPrims */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Int4
value;
  *C_integer;

 typedef struct
  /* C_real - COMPILED XPrims */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Real10
value;
  *C_real;
 typedef struct
  /* C_list - COMPILED XPrims */
 
  Int2
 type;
/* internal use only */
  Nat4
 save;
/* internal use only */
  Nat4
 use;
/* number of references */
  Nat4
 length; /* length of list  */
  C_object
*data[];
  *C_list;
 typedef struct
  /* C_string - COMPILED XPrims */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Nat4
length; /* length of string */
  Nat1
text[];
  *C_string;

 typedef struct
  /* C_instance - COMPILED XPrims */
 
  Int2
 type;
/* internal use only */
  Nat4
 save;
/* internal use only */
  Nat4
 use;
/* number of references */
  C_object
*attrs[];
  *C_instance;
 
 typedef struct
/* C_Point - COMPILED XPrims */
 
  Int2
type;
 /* internal use only */ 
  
  Nat4
save;
 /* internal use only */
  
  Nat4
use;
 /* number of references */
  
  Point
value;
  *C_Point;
 
 typedef struct
/* C_Ptr - COMPILED XPrims */
 
  Int2
type;
 /* internal use only */ 
  
  Nat4
save;
 /* internal use only */
  
  Nat4
use;
 /* number of references */

  Int2
reftype
/* Compiled only */
 
  Ptr
value;
  *C_Ptr;
 
 typedef struct
/* C_Handle - COMPILED XPrims */
 
  Int2
type;
 /* internal use only */ 
  
  Nat4
save;
 /* internal use only */
  
  Nat4
use;
 /* number of references */

  Int2
reftype
/* Compiled only */
 
  Handle
value;
  *C_Handle;

Data Types in XCode*530*

This section describes C declarations of the Prograph data types for XCode. Two sets of declarations are shown, the second of which uses THINK 4.0 C object extensions. If you are using MPW C or THINK 3.0 C (or if you are using THINK 4.0 C and don’t wish to take advantage of objects) then the first set of declarations apply.

XCode declarations:  *530*

 typedef struct
  /* C_object - XCode */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
   *C_object;

 typedef struct
  /* C_none - XCode */

  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  *C_none;

 typedef struct
  /* C_undefined - XCode */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  *C_undefined;
 
 typedef struct
  /* C_boolean - XCode */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Bool
value;
  *C_boolean;

 typedef struct
  /* C_integer - XCode */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Int4
 value;
  *C_integer;

 typedef struct
  /* C_real - XCode */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Real10
value;
  *C_real;
 typedef struct
  /* C_list - XCode */
 
  Int2
 type;
/* internal use only */
  Nat4
 save;
/* internal use only */
  Nat4
 use;
/* number of references */
  Nat4
 length; /* length of list  */
  C_object
*data[];
  *C_list;
 typedef struct
  /* C_string - XCode */
 
  Int2
type;
/* internal use only */
  Nat4
save;
/* internal use only */
  Nat4
use;
/* number of references */
  Nat4
length; /* length of string */
  Nat1
text[];
  *C_string;

 typedef struct
  /* C_instance - XCode */
 
  Int2
 type;
/* internal use only */
  Nat4
 save;
/* internal use only */
  Nat4
 use;
/* number of references */
  C_object
*attrs[];
  *C_instance;
 
 typedef struct
/* C_Point - XCode */
 
  Int2
type;
 /* internal use only */ 
  
  Nat4
save;
 /* internal use only */
  
  Nat4
use;
 /* number of references */
  
  Point
value;
  *C_Point;
 
 typedef struct
/* C_Ptr - XCode */
 
  Int2
type;
 /* internal use only */ 
  
  Nat4
save;
 /* internal use only */
  
  Nat4
use;
 /* number of references */

  Int2
reftype
/* type of Ptr */
 
  Ptr
value;
  *C_Ptr;
 
 typedef struct
/* C_Handle - XCode */
 
  Int2
type;
 /* internal use only */ 
  
  Nat4
save;
 /* internal use only */
  
  Nat4
use;
 /* number of references */

  Int2
reftype
/* type of Handle */
 
  Handle
value;
  *C_Handle; 

XCode THINK C object declarations:  *532*

 struct C_object :   indirect
 /* C_object - XCode OBJECT C */
 
               /* type field is hidden */
  Nat4
 save;
      /* internal use only */
  Nat4
 use;
      /* count of references */

 struct C_none :   C_object
  /* C_none - XCode OBJECT C */
  
 ; 

 struct C_boolean :   C_object
 /* C_boolean-XCode OBJECT C */
 
  Bool
value;
 ;

 struct C_number :   C_object
 /* C_number - XCode OBJECT C */
 
 ;

 struct C_integer :   C_number
 /* C_integer-XCode OBJECT C */
 
  Int4
 value;
 ;

 struct C_real :   C_number
  /* C_real - XCode OBJECT C */
 
  Real10
value; 
 ;

 struct C_list :   C_object 
  /* C_list - XCode OBJECT C */
 
  Nat4
 length; 
  C_object
*data[];
 ;

 struct C_string :   C_object
 /* C_string-XCode OBJECT C */
 
  Nat4
length; 
  Nat1
text[];
 ;

 struct
C_instance :    C_object
/* C_instance-XCode OBJECT C */
 
  C_object
*attrs[];
 ;

 struct C_macintosh :   C_object
/* C_macintosh-XCode OBJECT C */
 
 ;

 struct C_Point:   C_macintosh 
/* C_Point - XCode OBJECT C */

  Point
value;
 ;

 struct C_Ptr:   C_macintosh 
 /* C_Ptr - XCode OBJECT C */

  Int2
 type; 
      /* type of Ptr */
  Ptr  
 value;
 ;

 struct C_Handle:   C_macintosh 
 /* C_Handle - XCode OBJECT C */

  Int2
 type; 
      /* type of handle */
  Handle  
value;
 ;

 Use Counts *533*

Prograph is a dataflow language.  Whereas traditional programming languages rely on the storage of data in variables, Prograph treats data items as constants.  This allows the same data item to be shared by multiple processes.  Data can be created, used, and destroyed, but it can never be altered. 

The use field in every data item, also known as the use count, contains the number of references to that item.  When writing primitives, it is important to understand and properly maintain the use count.

When the use count of a data item falls to zero, Prograph automatically releases the memory occupied by that item.  If you don’t increment a use count appropriately, Prograph may destroy an item that is still referenced. If you fail to decrement a use count appropriately, a data item will continue to occupy space after it is no longer needed.

Whenever a new reference is made to a data item, the use count of the item must be incremented.  You can do so by passing the item to the IncUse function.*534*
Whenever a reference to a data item is removed, you must decrement its use count by passing the item to the DecUse function.  You should never decrement the use field directly.

In a Prograph program, there are four places where references can be made to data items:    the value of an output root, the attribute slot of an instance, the data slot of a list, and the value of a persistent.

You could write a primitive, for instance, that takes a string as input, adds the string to a list, and returns the string as output. The string has a certain use count when it is passed to your primitive (and may be referenced by many other operations). When you assign the string to the list, this constitutes an additional reference, so you must increment the string’s use count. When you pass the string out, that is another reference, and the use count must be incremented once again.

Two of the Prograph data types are an exception to the “no alteration” rule.  Lists and instances of user-defined classes are considered memory-based structures, and the data in their slots can be replaced with different data items.*534*

CAUTION:    The size of C_list data items should not be altered. You should instead make a copy of the C_list using the Duplicate function and then manipulate the copy. 

To replace the value of a data slot, first assign the current value of the slot to a temporary variable. Then pass the replacing value to the IncUse function and assign it to the data slot. Finally, pass the value in the temporary variable to the DecUse function. 

Always call IncUse before DecUse. When the value of a data slot is being replaced it may be that the current data item is the same as the replacing data item. If DecUse is called first and the data item’s use count is one then DecUse will release the memory occupied by the data item. Calling IncUse before DecUse ensures against unintended destruction of data items.

Functions are supplied for creating all of the Prograph data types, as well as for the Macintosh-specific types C_Handle, C_Ptr, C_Point, C_Rect, and C_RGBColor.  When you use these functions to create a data item, the use count is automatically set to one.*534*

If your primitive does not place the data item in an output root, list, instance or persistent, no permanent reference is made to that item.  In this case, simply pass the item to the DecUse function so that its memory can be reclaimed.*535*

If your primitive makes a single permanent reference to the item—passing it out of the primitive, or assigning it to a list, for example—it is not necessary to increase the use count.

A number of functions are also supplied for manipulating lists and instances.  Each of these functions accept flags specifying whether or not to automatically adjust the uses counts.  If the data item being assigned to a list or an instance is created within your primitive, and will not be passed to an output root, it is not necessary to increment the use count.  Conversely, if a data item contained in a list or in an instance is to be output from the primitive without being removed from the list or instance, this new reference requires that the item’s use count be incremented.

 Arity Macros *535*

The register D0 is used to pass the actual arity to a method. In interpreted code this must always be done. In compiled code it is necessary before any variable-arity method is called. A number of useful macros are provided for the purpose of accessing and setting the arity. 

GETARITY(A,B) GETARITY returns the inarity (number of inputs) in A and the outarity (number of outputs) in B.

GETINARITY(A) GETINARITY returns the inarity in A.

GETOUTARITY(A) GETOUTARITY returns the outarity in A.

VARITY(A,B,C,D,E ) VARITY is used in methods with a varying number of inputs and outputs. You pass the first data argument in A, and it returns the input arity in B, the output arity in C, the array of input arguments in D, and the array of pointers to output arguments in E. 

SETARITY(A,B) SETARITY places the inarity and outarity passed in A and B into register D0. 
*535*

The macros which get the arity should be the first thing called in your function since the value of register D0 may change. Also use only one of the get arity macros in any one function.